home *** CD-ROM | disk | FTP | other *** search
/ Visual Cafe 3 / Visual Cafe 3.ISO / Vcafe / Main.bin / Beans.java < prev    next >
Text File  |  1998-09-22  |  15KB  |  476 lines

  1. /*
  2.  * @(#)Beans.java    1.31 98/07/01
  3.  *
  4.  * Copyright 1996-1998 by Sun Microsystems, Inc.,
  5.  * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
  6.  * All rights reserved.
  7.  * 
  8.  * This software is the confidential and proprietary information
  9.  * of Sun Microsystems, Inc. ("Confidential Information").  You
  10.  * shall not disclose such Confidential Information and shall use
  11.  * it only in accordance with the terms of the license agreement
  12.  * you entered into with Sun.
  13.  */
  14.  
  15. package java.beans;
  16.  
  17. import java.io.*;
  18. import java.awt.*;
  19. import java.applet.*;
  20. import java.net.URL;
  21. import java.lang.reflect.Array;
  22.  
  23. /**
  24.  * This class provides some general purpose beans control methods.
  25.  */
  26.  
  27. public class Beans {
  28.  
  29.     /**
  30.      * Instantiate a bean.
  31.      * <p>
  32.      * The bean is created based on a name relative to a class-loader.
  33.      * This name should be a dot-separated name such as "a.b.c".
  34.      * <p>
  35.      * In Beans 1.0 the given name can indicate either a serialized object
  36.      * or a class.  Other mechanisms may be added in the future.  In
  37.      * beans 1.0 we first try to treat the beanName as a serialized object
  38.      * name then as a class name.
  39.      * <p>
  40.      * When using the beanName as a serialized object name we convert the
  41.      * given beanName to a resource pathname and add a trailing ".ser" suffix.
  42.      * We then try to load a serialized object from that resource.
  43.      * <p>
  44.      * For example, given a beanName of "x.y", Beans.instantiate would first
  45.      * try to read a serialized object from the resource "x/y.ser" and if
  46.      * that failed it would try to load the class "x.y" and create an
  47.      * instance of that class.
  48.      * <p>
  49.      * If the bean is a subtype of java.applet.Applet, then it is given
  50.      * some special initialization.  First, it is supplied with a default
  51.      * AppletStub and AppletContext.  Second, if it was instantiated from 
  52.      * a classname the applet's "init" method is called.  (If the bean was
  53.      * deserialized this step is skipped.) 
  54.      * <p>
  55.      * Note that for beans which are applets, it is the caller's responsiblity
  56.      * to call "start" on the applet.  For correct behaviour, this should be done
  57.      * after the applet has been added into a visible AWT container.
  58.      * <p>
  59.      * Note that applets created via beans.instantiate run in a slightly
  60.      * different environment than applets running inside browsers.  In
  61.      * particular, bean applets have no access to "parameters", so they may 
  62.      * wish to provide property get/set methods to set parameter values.  We
  63.      * advise bean-applet developers to test their bean-applets against both
  64.      * the JDK appletviewer (for a reference browser environment) and the
  65.      * BDK BeanBox (for a reference bean container).
  66.      * 
  67.      * @param     classLoader the class-loader from which we should create
  68.      *                       the bean.  If this is null, then the system
  69.      *                        class-loader is used.
  70.      * @param     beanName    the name of the bean within the class-loader.
  71.      *                     For example "sun.beanbox.foobah"
  72.      * @exception java.lang.ClassNotFoundException if the class of a serialized
  73.      *              object could not be found.
  74.      * @exception java.io.IOException if an I/O error occurs.
  75.      */
  76.     public static Object instantiate(ClassLoader cls, String beanName) 
  77.             throws java.io.IOException, ClassNotFoundException {
  78.  
  79.     java.io.InputStream ins;
  80.     java.io.ObjectInputStream oins = null;
  81.     Object result = null;
  82.     boolean serialized = false;
  83.  
  84.     // Try to find a serialized object with this name
  85.     String serName = beanName.replace('.','/').concat(".ser");
  86.     if (cls == null) {
  87.         ins = ClassLoader.getSystemResourceAsStream(serName);
  88.     } else {
  89.         ins  = cls.getResourceAsStream(serName);
  90.     }
  91.     if (ins != null) {
  92.         try {
  93.             if (cls == null) {
  94.             oins = new ObjectInputStream(ins);
  95.             } else {
  96.             oins = new ObjectInputStreamWithLoader(ins, cls);
  97.             }
  98.             result = oins.readObject();
  99.         serialized = true;
  100.             oins.close();
  101.         } catch (java.io.IOException ex) {
  102.         ins.close();
  103.         // For now, drop through and try opening the class.
  104.         // throw ex;
  105.         } catch (ClassNotFoundException ex) {
  106.         ins.close();
  107.         throw ex;
  108.         }
  109.     }
  110.  
  111.     if (result == null) {
  112.         // No serialized object, try just instantiating the class
  113.         Class cl;
  114.         if (cls == null) {
  115.             cl = Class.forName(beanName);
  116.         } else {
  117.             cl = cls.loadClass(beanName);
  118.         }
  119.         try {
  120.             result = cl.newInstance();
  121.         } catch (Exception ex) {
  122.             throw new ClassNotFoundException();
  123.         }
  124.     }
  125.     // Ok, if the result is an applet initialize it.
  126.     if (result != null && result instanceof Applet) {
  127.         Applet applet = (Applet) result;
  128.  
  129.         // Figure our the codebase and docbase URLs.  We do this
  130.         // by locating the URL for a known resource, and then
  131.         // massaging the URL.
  132.  
  133.         // First find the "resource name" corresponding to the bean
  134.         // itself.  So a serialzied bean "a.b.c" would imply a resource
  135.         // name of "a/b/c.ser" and a classname of "x.y" would imply
  136.         // a resource name of "x/y.class".
  137.  
  138.         String resourceName;
  139.         if (serialized) {
  140.         // Serialized bean
  141.         resourceName = beanName.replace('.','/').concat(".ser");
  142.         } else {
  143.         // Regular class
  144.         resourceName = beanName.replace('.','/').concat(".class");
  145.         }
  146.         URL objectUrl = null;
  147.         URL codeBase = null;
  148.         URL docBase = null;
  149.  
  150.         // Now get the URL correponding to the resource name.
  151.         if (cls == null) {
  152.         objectUrl = ClassLoader.getSystemResource(resourceName);
  153.         } else {
  154.         objectUrl = cls.getResource(resourceName);
  155.         }
  156.  
  157.         // If we found a URL, we try to locate the docbase by taking
  158.         // of the final path name component, and the code base by taking
  159.            // of the complete resourceName.
  160.         // So if we had a resourceName of "a/b/c.class" and we got an
  161.         // objectURL of "file://bert/classes/a/b/c.class" then we would
  162.         // want to set the codebase to "file://bert/classes/" and the
  163.         // docbase to "file://bert/classes/a/b/"
  164.  
  165.         if (objectUrl != null) {
  166.         String s = objectUrl.toExternalForm();
  167.         if (s.endsWith(resourceName)) {
  168.               int ix = s.length() - resourceName.length();
  169.             codeBase = new URL(s.substring(0,ix));
  170.             docBase = codeBase;
  171.             ix = s.lastIndexOf('/');
  172.             if (ix >= 0) {
  173.                 docBase = new URL(s.substring(0,ix+1));
  174.             }
  175.         }
  176.         }
  177.                 
  178.         // Setup a default context and stub.
  179.         BeansAppletContext context = new BeansAppletContext(applet);
  180.         BeansAppletStub stub = new BeansAppletStub(applet, context, codeBase, docBase);
  181.         applet.setStub(stub);
  182.  
  183.         // If it was deserialized then it was already init-ed.  Otherwise
  184.         // we need to initialize it.
  185.         if (!serialized) {
  186.         // We need to set a reasonable initial size, as many
  187.         // applets are unhappy if they are started without 
  188.         // having been explicitly sized.
  189.         applet.setSize(100,100);
  190.         applet.init();
  191.         }
  192.         stub.active = true;
  193.     }
  194.     return result;
  195.     }
  196.  
  197.  
  198.     /**
  199.      * From a given bean, obtain an object representing a specified
  200.      * type view of that source object. 
  201.      * <p>
  202.      * The result may be the same object or a different object.  If
  203.      * the requested target view isn't available then the given
  204.      * bean is returned.
  205.      * <p>
  206.      * This method is provided in Beans 1.0 as a hook to allow the
  207.      * addition of more flexible bean behaviour in the future.
  208.      *
  209.      * @param obj  Object from which we want to obtain a view.
  210.      * @param targetType  The type of view we'd like to get.
  211.      *
  212.      */
  213.     public static Object getInstanceOf(Object bean, Class targetType) {
  214.         return bean;
  215.     }
  216.  
  217.     /**
  218.      * Check if a bean can be viewed as a given target type.
  219.      * The result will be true if the Beans.getInstanceof method
  220.      * can be used on the given bean to obtain an object that
  221.      * represents the specified targetType type view.
  222.      *
  223.      * @param bean  Bean from which we want to obtain a view.
  224.      * @param targetType  The type of view we'd like to get.
  225.      * @return "true" if the given bean supports the given targetType.
  226.      */
  227.     public static boolean isInstanceOf(Object bean, Class targetType) {
  228.     return Introspector.isSubclass(bean.getClass(), targetType);
  229.     }
  230.  
  231.  
  232.     /**
  233.      * Test if we are in design-mode.
  234.      *
  235.      * @return  True if we are running in an application construction
  236.      *        environment.
  237.      */
  238.     public static boolean isDesignTime() {
  239.     return designTime;
  240.     }
  241.  
  242.     /**
  243.      * @return  True if we are running in an environment where beans
  244.      *       can assume that an interactive GUI is available, so they 
  245.      *       can pop up dialog boxes, etc.  This will normally return
  246.      *       true in a windowing environment, and will normally return
  247.      *       false in a server environment or if an application is
  248.      *       running as part of a batch job.
  249.      */
  250.     public static boolean isGuiAvailable() {
  251.     return guiAvailable;
  252.     }
  253.  
  254.     /**
  255.      * Used to indicate whether of not we are running in an application
  256.      * builder environment.  Note that this method is security checked
  257.      * and is not available to (for example) untrusted applets.
  258.      *
  259.      * @param isDesignTime  True if we're in an application builder tool.
  260.      */
  261.  
  262.     public static void setDesignTime(boolean isDesignTime)
  263.             throws SecurityException {
  264.     designTime = isDesignTime;
  265.     }
  266.  
  267.     /**
  268.      * Used to indicate whether of not we are running in an environment
  269.      * where GUI interaction is available.  Note that this method is 
  270.      * security checked and is not available to (for example) untrusted
  271.      * applets.
  272.      *
  273.      * @param isGuiAvailable  True if GUI interaction is available.
  274.      */
  275.  
  276.     public static void setGuiAvailable(boolean isGuiAvailable)
  277.             throws SecurityException {
  278.     guiAvailable = isGuiAvailable;
  279.     }
  280.  
  281.  
  282.     private static boolean designTime;
  283.     private static boolean guiAvailable = true;
  284. }
  285.  
  286. /**
  287.  * This subclass of ObjectInputStream delegates loading of classes to
  288.  * an existing ClassLoader.
  289.  */
  290.  
  291. class ObjectInputStreamWithLoader extends ObjectInputStream
  292. {
  293.     private ClassLoader loader;
  294.  
  295.     /**
  296.      * Loader must be non-null;
  297.      */
  298.  
  299.     public ObjectInputStreamWithLoader(InputStream in, ClassLoader loader)
  300.         throws IOException, StreamCorruptedException {
  301.  
  302.     super(in);
  303.     if (loader == null) {
  304.             throw new IllegalArgumentException("Illegal null argument to ObjectInputStreamWithLoader");
  305.     }
  306.     this.loader = loader;
  307.     }
  308.  
  309.     /**
  310.      * Make a primitive array class
  311.      */
  312.  
  313.     private Class primitiveType(char type) {
  314.     switch (type) {
  315.     case 'B': return byte.class;
  316.         case 'C': return char.class;
  317.     case 'D': return double.class;
  318.     case 'F': return float.class;
  319.     case 'I': return int.class;
  320.     case 'J': return long.class;
  321.     case 'S': return short.class;
  322.     case 'Z': return boolean.class;
  323.     default: return null;
  324.     }
  325.     }
  326.  
  327.     /**
  328.      * Use the given ClassLoader rather than using the system class
  329.      */
  330.     protected Class resolveClass(ObjectStreamClass classDesc)
  331.     throws IOException, ClassNotFoundException {
  332.  
  333.     String cname = classDesc.getName();
  334.     if (cname.startsWith("[")) {
  335.         // An array
  336.         Class component;        // component class
  337.         int dcount;            // dimension
  338.         for (dcount=1; cname.charAt(dcount)=='['; dcount++) ;
  339.         if (cname.charAt(dcount) == 'L') {
  340.         component = loader.loadClass(cname.substring(dcount+1,
  341.                                  cname.length()-1));
  342.         } else {
  343.         if (cname.length() != dcount+1) {
  344.             throw new ClassNotFoundException(cname);// malformed
  345.         }
  346.         component = primitiveType(cname.charAt(dcount));
  347.         }
  348.         int dim[] = new int[dcount];
  349.         for (int i=0; i<dcount; i++) {
  350.         dim[i]=0;
  351.         }
  352.         return Array.newInstance(component, dim).getClass();
  353.     } else {
  354.         return loader.loadClass(cname);
  355.     }
  356.     }
  357. }
  358.  
  359. /**
  360.  * Package private support class.  This provides a default AppletContext
  361.  * for beans which are applets.
  362.  */
  363.  
  364. class BeansAppletContext implements AppletContext {
  365.     Applet target;
  366.     java.util.Hashtable imageCache = new java.util.Hashtable();
  367.  
  368.     BeansAppletContext(Applet target) {
  369.         this.target = target;
  370.     }
  371.  
  372.     public AudioClip getAudioClip(URL url) {
  373.     // We don't currently support audio clips in the Beans.instantiate
  374.     // applet context, unless by some luck there exists a URL content
  375.     // class that can generate an AudioClip from the audio URL.
  376.     try {
  377.         return (AudioClip) url.getContent();
  378.       } catch (Exception ex) {
  379.         return null;
  380.     }
  381.     }
  382.  
  383.     public synchronized Image getImage(URL url) {
  384.     Object o = imageCache.get(url);
  385.     if (o != null) {
  386.         return (Image)o;
  387.     }
  388.     try {
  389.         o = url.getContent();
  390.         if (o == null) {
  391.         return null;
  392.         }
  393.         if (o instanceof Image) {
  394.         imageCache.put(url, o);
  395.         return (Image) o;
  396.         }
  397.         // Otherwise it must be an ImageProducer.
  398.         Image img = target.createImage((java.awt.image.ImageProducer)o);
  399.         imageCache.put(url, img);
  400.         return img;
  401.  
  402.       } catch (Exception ex) {
  403.         return null;
  404.     }
  405.     }
  406.  
  407.     public Applet getApplet(String name) {
  408.     return null;
  409.     }
  410.  
  411.     public java.util.Enumeration getApplets() {
  412.     java.util.Vector applets = new java.util.Vector();
  413.     applets.addElement(target);
  414.     return applets.elements();    
  415.     }
  416.  
  417.     public void showDocument(URL url) {
  418.     // We do nothing.
  419.     }
  420.  
  421.     public void showDocument(URL url, String target) {
  422.     // We do nothing.
  423.     }
  424.  
  425.     public void showStatus(String status) {
  426.     // We do nothing.
  427.     }
  428. }
  429.  
  430. /**
  431.  * Package private support class.  This provides an AppletStub
  432.  * for beans which are applets.
  433.  */
  434. class BeansAppletStub implements AppletStub {
  435.     transient boolean active;
  436.     transient Applet target;
  437.     transient AppletContext context;
  438.     transient URL codeBase;
  439.     transient URL docBase;
  440.  
  441.     BeansAppletStub(Applet target,
  442.         AppletContext context, URL codeBase, 
  443.                 URL docBase) {
  444.         this.target = target;
  445.     this.context = context;
  446.     this.codeBase = codeBase;
  447.     this.docBase = docBase;
  448.     }
  449.  
  450.     public boolean isActive() {
  451.     return active;
  452.     }
  453.     
  454.     public URL getDocumentBase() {
  455.     // use the root directory of the applet's class-loader
  456.     return docBase;
  457.     }
  458.  
  459.     public URL getCodeBase() {
  460.     // use the directory where we found the class or serialized object.
  461.     return codeBase;
  462.     }
  463.  
  464.     public String getParameter(String name) {
  465.     return null;
  466.     }
  467.  
  468.     public AppletContext getAppletContext() {
  469.     return context;
  470.     }
  471.  
  472.     public void appletResize(int width, int height) {
  473.     // we do nothing.
  474.     }
  475. }
  476.